package top.maof.lightsearch.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.Query;
import top.maof.lightsearch.annotation.Key;
import top.maof.lightsearch.annotation.Property;
import top.maof.lightsearch.annotation.Type;
import top.maof.lightsearch.exception.LightException;
import top.maof.lightsearch.exception.NoKeyException;
import top.maof.lightsearch.exception.NoTypeException;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;

@Slf4j
public final class LightUtils {

    public static <T> Object key(T t) throws NoKeyException {
        Class<?> aClass = t.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field f : declaredFields) {
            Key key = f.getAnnotation(Key.class);
            if (key == null) {
                continue;
            }
            try {
                f.setAccessible(true);
                return f.get(t);
            } catch (IllegalAccessException e) {
                log.error("IllegalAccessException entity: {}", t);
                throw new NoKeyException();
            }
        }
        throw new NoKeyException();
    }


    public static float weight(Field field) {
        float weight = 1f;
        Key key = field.getAnnotation(Key.class);
        if (key != null) {
            weight = (float) key.weight();
        } else {
            Property property = field.getAnnotation(Property.class);
            weight = (float) property.weight();
        }
        return weight;
    }

    /**
     * 获取lucene Filed 的键
     */
    public static String fieldKey(String typeValue, String propertyValue) {
        return new StringBuilder(typeValue).append(".").append(propertyValue).toString();
    }

    /**
     * 获取lucene Filed 的键
     */
    public static <T> String fieldKey(Class<T> clazz, PropertyFunction<T> pf) throws LightException {
        Field field = field(clazz, pf);

        String propertyKey = null;

        Key key = field.getAnnotation(Key.class);

        Property annotation = field.getAnnotation(Property.class);

        if (annotation != null) {
            propertyKey = annotation.value();
        }

        if (key != null) {
            propertyKey = key.value();
        }

        if (propertyKey == null) {
            throw new NoKeyException();
        }
        Type type = (Type) clazz.getAnnotation(Type.class);

        String typeKey = null;

        if (type != null) {
            typeKey = type.value();
        } else {
            throw new NoTypeException();
        }

        return fieldKey(typeKey, propertyKey);
    }


    public static <T> String fieldKey(Class<T> clazz, PropertyFunction<T> pf, Field field) throws LightException {

        String propertyKey = null;

        Property annotation = field.getAnnotation(Property.class);

        if (annotation != null) {
            propertyKey = annotation.value();
        }

        Key key = field.getAnnotation(Key.class);

        if (key != null) {
            propertyKey = key.value();
        }


        if (propertyKey == null) {
            throw new NoKeyException();
        }

        Type type = (Type) clazz.getAnnotation(Type.class);

        String typeKey = null;

        if (type != null) {
            typeKey = type.value();
        } else {
            throw new NoTypeException();
        }

        return fieldKey(typeKey, propertyKey);
    }

    public static <T> Field field(Class clazz, PropertyFunction<T> pf) {

        Method method = null;

        try {
            method = pf.getClass().getDeclaredMethod("writeReplace");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        method.setAccessible(true);
        SerializedLambda serializedLambda = null;
        try {
            serializedLambda = (SerializedLambda) method.invoke(pf);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        String getterMethodName = serializedLambda.getImplMethodName();
        String filedName = "";
        if (getterMethodName.startsWith("is")) {
            filedName = getterMethodName.substring(2);
        } else if (getterMethodName.startsWith("get") || getterMethodName.startsWith("set")) {
            filedName = getterMethodName.substring(3);
        }

        if (filedName.length() == 1 ||
                (filedName.length() > 1 && !Character.isUpperCase(filedName.charAt(1)))) {
            filedName = filedName.substring(0, 1).toLowerCase(Locale.ENGLISH) + filedName.substring(1);
        }


        Field field = null;
        try {
            field = clazz.getDeclaredField(filedName);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        return field;
    }
}
